# from django.shortcuts import render
# from rest_framework.views import APIView
# from rest_framework.response import Response
# from captcha.image import ImageCaptcha
# from django.http import HttpResponse
# from django.db.models import Q
# from django.contrib.auth.hashers import check_password
# from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
# import random
# import string
# import redis
# # Create your views here.
# from myapp.models import *
#
#
# # 校验用户名是否存在
# class CheckUserName(APIView):
#     def get(self, request, name):
#         rest = Users.objects.filter(username=name).count()
#         if rest > 0:
#             return Response(
#                 {'msg': '用户名已经存在', 'code': 400}
#             )
#         return Response({'code': 200})
#
#
# # 校验手机号是否存在
# class CheckMobile(APIView):
#     def get(self, request, mobile):
#         rest = Users.objects.filter(mobile=mobile).count()
#         if rest > 0:
#             return Response(
#                 {'msg': '手机号已经存在', 'code': 400}
#             )
#         return Response({'code': 200})
#
#
# # 生成图片验证码
# class TuCode(APIView):
#     def get(self, request, uuid):
#         salt = ''.join(random.sample(string.ascii_letters + string.digits, 4))
#         img = ImageCaptcha()
#         image = img.generate(salt)
#         redis_cli = redis.Redis(host='127.0.0.1', port=6379)
#         imgid = 'img_{}'.format(uuid)
#         redis_cli.setex(imgid, 300, salt)
#         return HttpResponse(image, content_type='image/png')
#
#
# # 校验图片验证码
# class CheckTu(APIView):
#     def get(self, request):
#         img_uuid = request.query_params.get('imageCodeID')
#         image_code_ = request.query_params.get('imageCode')
#         redis_cli = redis.Redis(host='127.0.0.1', port=6379)
#         image_code = redis_cli.get('img_{}'.format(img_uuid))
#         if not image_code:
#             return Response({'msg': '验证码过期','code': 204})
#         if image_code.decode().lower() == image_code_.lower():
#             return Response({'msg': 'ok', 'code': 200})
#         else:
#             return Response({'msg': '验证码错误', 'code': 204})
#
#
# # 注册
# class CheckRegister(APIView):
#     def post(self, request):
#         name = request.data.get('userName')
#         pwd = request.data.get('pwd')
#         mobile = request.data.get('mobile')
#         agree = request.data.get('agree')
#         if not all([name, pwd, mobile]):
#             return Response(
#                 {'msg': '请输入完整的信息', 'code': 400}
#             )
#         if not agree:
#             return Response(
#                 {'msg': '请勾选同意协议', 'code': 400}
#             )
#         Users.objects.create_user(username=name, password=pwd, mobile=mobile)
#         return Response({'msg': '注册成功', 'code': 200})
#
#
# # 登录
# class UserLogin(APIView):
#     def post(self, request):
#         user_name = request.data.get('user')
#         pwd = request.data.get("pwd")
#         try:
#             user = Users.objects.get(Q(username=user_name) | Q(mobile=user_name))
#         except Users.DoesNotExist as e:
#             return Response({'msg': '用户不存在，请重新登录', 'code': 400})
#         check = check_password(pwd, user.password)
#         if check:
#             payload = jwt_payload_handler(user)
#             token = jwt_encode_handler(payload)
#             request.session["username"] = user_name
#             return Response({"code": 200, "msg": "登录成功", 'token': token, 'user': {"userName": user.username}})
#             # resp = Response({"code": 200, "msg": "登录成功", 'token': token, 'user': {"userName": user.username}})
#             # resp.set_cookie('token', token)
#         else:
#             return Response({"code": 400, "msg": "用户名或密码不正确！"})
#
#
# # 退出
# class Logout(APIView):
#     def post(self, request):
#         """退出登录"""
#         print(request)
#         # 删除cookie
#         # Cookie是在什么时间生成的:
#         # token = request.COOKIES.get('token')
#         # if token:
#         #     del token
#         # return Response({'msg':"退出成功!", "code": 200})
#         if request.session.get('username'):
#             del request.session["username"]
#         return Response({'msg':"退出成功!", "code": 200})


# 老赵的代码
import random
import string
import redis
from django.contrib.auth.hashers import check_password
from django.http.response import HttpResponse
from django.contrib.auth import authenticate
from django.db.models import Q

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.utils import jwt_payload_handler,jwt_encode_handler

from .models import Users
from captcha.image import ImageCaptcha


# 校验用户名是否存在
class CheckUsername(APIView):
    def get(self, request, name):
        """
        判断用户名是否重复
        1.获取前端传来的用户名
        2. 校验, 数据中是否有此用户名
        3. 有的话说明已经存在
        """
        # 直接重数据库查询
        # 统计当前用户的数量
        rest = Users.objects.filter(username=name).count()
        if rest > 0:
            # 说明用户名已经存在
            return Response({'msg':"用户名已经存在","code":"400"})
        # 不存在
        return Response({"code":'200'})


# 校验手机号是否存在
class CheckMobile(APIView):
    def get(self, request, mobile):
        """判断手机号号是否重复"""
        rest = Users.objects.filter(mobile=mobile).count()
        if rest > 0:
            # 说明用户名已经存在
            return Response({'msg': "手机号已经存在", "code": "400"})
        # 不存在
        return Response({"code": '200'})


# 生成图片验证码
class GenerateImageCode(APIView):

    def get(self, request, img_id):
        """
        生成图片验证码
        1. 接收前端传来的uuid, 图片id
        2. 使用随机模块生成: 字符+数字的随机数,长度6
        3. 使用capch模块生成图片
        4. 返回生成的图片
        """
        # 使用随机模块生成: 字符+数字的随机数,长度6
        # 生成的是数字+字符的字符串: eg: asWE23  we34WE
        # string.ascii_letters  生成区分大小写的字符
        # string.digits: 生成0-9de 随机数字
        salt = ''.join(random.sample(string.ascii_letters + string.digits, 4))
        # 生成一张图片
        img = ImageCaptcha()
        # 把生成的随机数字添加图片上
        image = img.generate(salt)

        # 把生成的图片上的数字写入redis,便于后期校验
        # redis链接
        redis_cli = redis.Redis(host='localhost',port=6379)
        # 写入redis, 把生成的图片上的数字写入redis
        # 要使用redis的哪一种数据类型?String 为什么? key/v 格式就满足需求
        # 写入到redis有效期是300秒
        imgId = "img_{}".format(img_id)
        redis_cli.setex(imgId,300, salt)
        # 返回图片
        return HttpResponse(image, content_type="image/jpg")


# 校验图片验证码
class CheckImageCode(APIView):
    def get(self, request):
        """
        校验图片验证码
        1. 获取前端请求时传递来的图片id和用户输入的图片内容
        2. 根号有图片id去redis 中查询redis中保存的图片内容
        3. 对比redis中的内容和用户输入的是否一样
            1. 一样的返回成功
            2. 不一样的, 校验失败, 返回图片验证码输入错误
        """
        # 如何接收前端传来的参数
        # http请求传递参数
        # 1. 固定参数: http://127.0.0.1:8000/goods/1/                        goods/<int:id>/
        # 2. 查询字符串传参: http://127.0.0.1:8000/goods/?page=1&pagesize=20      goods/      request.query_params.get()
        # 3. 请求体中传参: form, 文件,        request.data.get()
        # 4. 请求头中传参: request.headers     cookie  session       request.Cookies.get()
        print(">>>>>>>>>>>>>>>>>>>>")
        image_id = request.query_params.get('imageCodeID')
        image_code = request.query_params.get('imageCode')
        # 根据前端传来的id 查询redis
        redis_cli = redis.Redis(host='localhost',port=6379)
        #查询redis 有可能获取到有可能获取不到
        result = redis_cli.get('img_{}'.format(image_id))
        # 能取出值
        if result:
            # 从redis中取出的值是byte字节,需要转码,转换成utf-8
            # 把redis内的字符转小写和用户输入的转小写,进行对比
            if result.decode().lower() != image_code.lower():
                return Response({'msg':"验证码输入错误!"})
            else:
                return Response({'code':200})
        # 取不出值, 验证码已经过期
        else:
            return Response({'msg':"验证码已经过期"})


# 注册
class UserRegister(APIView):
    def post(self, request):
        """
        注册业务逻辑(实现思路):
        1.获取request.data.get()中的数据,拿过来和数据中的字段比较: userName, pwd, mobile, agree
        2.如果字段一样,注册成功, 写入数据库
        7. 是否勾选
        """
        user_name = request.data.get('userName')
        pwd = request.data.get('pwd')
        mobile = request.data.get('mobile')
        agree = request.data.get('agree')
        # 后端要校验前端传来的数据
        # 只要有一个为空就错误
        if not all([user_name, pwd, mobile, agree]):
            return Response({'msg':"请输入完善注册用户信息","code":"400"})

        if not agree:
            # 说明没有同意协议
            return Response({"msg":"请勾选协议"})
        # 写入数据库
        # create()写入数据库时,密码是明文存储, 这是不安全的, 我们要以密文存储密码
        # create_user会把密码进行加密存储
        Users.objects.create_user(username=user_name, password=pwd,mobile=mobile, agree_rule=agree)
        return Response({'msg':"注册成功!","code":201})


# 登录
class Login(APIView):

    # 第2种多方式登录, 不用重写django的认证后端
    def post(self,request):
        """
        登录
        1. 获取前端传来的用户名和密码:
        2. 对前端传来的用户名和密码进行校验
        3. 校验成功返回,200状态码和登录的用户名
        4. 校验不成功的,返回400, 错误信息是用户名和密码错误
        """
        user_name = request.data.get('user')
        pwd = request.data.get('pwd')
        # 对前端传来的用户名和密码进行校验
        # 1. 校验前端传来的用户名是否存在数据库中
        try:
            user = Users.objects.get(Q(username=user_name) | Q(mobile=user_name))
        except Users.DoesNotExist as e:
            return Response({'msg':"此用户不存在,请先注册","code":400})
        # 2. 若存在数据库中, 前端传来的密码是否和数据库中的一样
        # TODO 数据库中的密码是密文存储的, 前端传来的是明文, 两个是不一样的,
        # 数据库的密码文是hash 加密,是不可逆的, 只能对前端传来的明文进行加密,然后对比是否一样
        is_correct = check_password(pwd, user.password)
        # 返回true,说明用户名和密码匹配
        if is_correct:
            # 生成token, 把生成的token返回
            # 传入第二部分的用户信息
            payload = jwt_payload_handler(user)
            # 根据第二部分生成token
            token = jwt_encode_handler(payload)
            # 把token 写入cookie,便于退出
            # 思考: cookie 是在响应中生成的还是在请求中生成的
            resp = Response({'msg':"登录成功","code":200,'user':{"userName":user.username},"token":token})
            # 设置cookie 中
            resp.set_cookie('token', token)
            return resp
        else:
            return Response({'msg':"用户名密码错误", "code":400})

    # 第一种多重方式登录
    # def post(self, request):
    #     """"""
    #     user_name = request.data.get('user')
    #     pwd = request.data.get('pwd')
    #     # 校验
    #     # 使用django的认证后端提供的authenticate方法进行校验, 传前端输入的用户名和密码
    #     user = authenticate(username=user_name, password=pwd)
    #     if user:
    #         # 生成token, 把生成的token返回
    #          # 传入第二部分的用户信息
    #         payload = jwt_payload_handler(user)
    #         # 根据第二部分生成token
    #         token = jwt_encode_handler(payload)
    #         return Response({'msg':"登录成功","code":200,'user':{"userName":user.username},"token":token})
    #     else:
    #         return Response({'msg': "用户名密码错误", "code": 400})


# 退出登录
class Logout(APIView):
    def post(self, request):
        """退出登录"""
        print(request)
        # 删除cookie
        # Cookie是在什么时间生成的:
        token = request.COOKIES.get('token')
        if token:
            del token
        return Response({'msg':"退出成功!", "code": 200})
